# -*- coding:utf-8 -*-
"""Created By Corvo"""

import weakref


class Rpc(object):
    _rpc_pass_key = ["Discard", "collection_name", "binding_flags", "binding_name"]  # 网易界面退出时会调用

    def __init__(self, mgr, identifier):
        self._mgr = weakref.proxy(mgr)
        self._identifier = identifier  # 调用匹配Id
        self._recall_map = {}
        self._recall_config = {}
        self._timer_map = {}
        self._function = RpcFunction(self)

    def __getattribute__(self, item):
        if item.startswith("_") or item in self._rpc_pass_key:
            return super(Rpc, self).__getattribute__(item)
        return self._function

    def __call__(self, target, *args, **kwargs):
        self._target = target
        param = len(args)
        if param == 1:
            self._recall_config = (args[0], kwargs.get("timeout", 5.0))
        elif param == 2:
            self._recall_config = args
        return self._function

    def _Trigger(self, function, *args):
        pack = {"data": args, "func": function, "identifier": self._identifier}
        if self._recall_config:
            self._ModifyRecall(pack, *self._recall_config)
            self._recall_config = None
        self._SynPack(pack)

    def _SynPack(self, pack):
        """同步数据"""
        print "[suc]", "同步数据"

    def _ModifyRecall(self, pack, recall, timeout):
        # type: (dict, any, float) -> None
        """修正回调"""

    def _DestroyRecall(self, uid):
        self._timer_map.pop(uid, None)
        return self._recall_map.pop(uid, None)


class RpcFunction(object):

    def __init__(self, rpc):
        self._bind_rpc = weakref.proxy(rpc)
        self._rpc_chain = []

    def __getattr__(self, item):
        self._rpc_chain.append(item)
        return self

    def __call__(self, *args, **kwargs):
        self._bind_rpc._Trigger(".".join(self._rpc_chain), *args)
        self._rpc_chain = []


class RpcServer(Rpc):

    def _SynPack(self, pack):
        _client = globals()["client"]  # type: Client
        _client.rpc._ModuleRpcSynDataEvent(pack)

    def _ModuleRpcSynDataEvent(self, args):
        if args["identifier"] != self._identifier:
            return
        if "server_recall" in args:
            if args["server_recall"] in self._recall_map:
                recall = self._DestroyRecall(args["server_recall"])
                if recall:
                    recall(args["data"])
            return
        method = getattr(self._mgr, args["func"])
        if not method:
            return
        res = method(*args.pop("data"))


class RpcClient(Rpc):

    def _SynPack(self, pack):
        _server = globals()["client"]  # type: Server
        _server.rpc._ModuleRpcSynDataEvent(pack)

    def _ModuleRpcSynDataEvent(self, args):
        # type: (dict) -> None
        if args["identifier"] != self._identifier:
            return
        if "client_recall" in args:
            if args["client_recall"] in self._recall_map:
                recall = self._DestroyRecall(args["client_recall"])
                if recall:
                    recall(args["data"])
            return
        chain_func = args["func"]  # type: str
        if not chain_func:
            return
        functions = chain_func.split(".")
        method = getattr(self._mgr, functions.pop(0))
        for target in functions:
            if not hasattr(method, target):
                print "[warn]", "方法不存在：", chain_func
                continue
            method = getattr(method, target)
        res = method(*args.pop("data"))


class Server(object):

    def __init__(self):
        super(Server, self).__init__()
        self.rpc = None
        self.Create()

    def Create(self):
        self.rpc = RpcServer(self, "player")

    @property
    def client(self, target=None):
        # type: (str) -> Client
        return self.rpc(target)


class Player(object):

    def Active(self):
        print "[suc]", "update"


class Client(object):

    def __init__(self):
        super(Client, self).__init__()
        self.rpc = None
        self.player = Player()
        self.Create()

    def Create(self):
        self.rpc = RpcClient(self, "player")

    def Function(self):
        print "[suc]", "Function"

    @property
    def server(self):
        # type: () -> Server
        return self.rpc


if __name__ == '__main__':
    server = Server()
    client = Client()

    server.client.player.Active()
